/****************************************
 * Copyright (c) 2015 NiuWa.
 * All rights reserved.
 * Created on 2015年4月15日
 * 
 * Contributors:
 * 	   Percy.Lo - initial implementation
 ****************************************/
package com.niuwa.p2p.server.utils.plugins;

import java.sql.Connection;
import java.sql.Statement;
import java.util.LinkedList;
import java.util.List;
import java.util.Map.Entry;
import java.util.Properties;

import org.apache.ibatis.executor.statement.BaseStatementHandler;
import org.apache.ibatis.executor.statement.RoutingStatementHandler;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.plugin.Signature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.niuwa.p2p.server.utils.ReflectUtil;

/**
 * @title StatementHandler的拦截器
 * 
 * @author Percy.Lo
 * @version 1.0
 * @created 2015年4月16日
 */
@Intercepts({ @Signature(type = StatementHandler.class, method = "prepare", args = { Connection.class }),
			  @Signature(type = StatementHandler.class, method = "update", args = { Statement.class })})
public class StatementHandlerInterceptor implements Interceptor {

	private final Logger logger = LoggerFactory.getLogger(this.getClass());

	private final List<PluginBean> pluginBeanList = new LinkedList<PluginBean>();// StatementHandler插件列表

	/**
	 * 拦截处理
	 */
	@Override
	public Object intercept(Invocation ivk) throws Throwable {
		if (ivk.getTarget() instanceof RoutingStatementHandler) {
			RoutingStatementHandler statementHandler = (RoutingStatementHandler) ivk.getTarget();
			BaseStatementHandler delegate = (BaseStatementHandler) ReflectUtil.getValueByFieldName(statementHandler, "delegate");
			MappedStatement mappedStatement = (MappedStatement) ReflectUtil.getValueByFieldName(delegate, "mappedStatement");
			for (PluginBean plugin : pluginBeanList) {
				if (mappedStatement.getId().matches(plugin.getSqlIdReg())) {
					return plugin.getClazz().intercept(ivk);
				}
			}
		}
		return ivk.proceed();
	}

	/**
	 * plugin处理
	 */
	@Override
	public Object plugin(Object target) {
		// 当目标类是StatementHandler类型时，才包装目标类，否者直接返回目标本身,减少目标被代理的次数
		if (target instanceof StatementHandler) {
			return Plugin.wrap(target, this);
		} else {
			return target;
		}
	}

	/**
	 * 加载properties
	 */
	@Override
	public void setProperties(Properties ps) {
		if (ps.size() == 0) {
			logger.error("plugin [StatementHandlerInterceptor] --> property size is zero!");
			return;
		}
		for (Entry<Object, Object> p : ps.entrySet()) {
			String clazz = p.getKey().toString();
			String value = p.getValue().toString();
			try {
				int idx = value.indexOf("@");
				String sqlIdReg = value, parameter = null;
				if (idx != -1) {
					sqlIdReg = value.substring(0, idx);
					parameter = value.substring(idx + 1);
				}
				IPlugin pluin = (IPlugin) Class.forName(clazz).newInstance();
				pluin.init(parameter);
				pluginBeanList.add(new PluginBean(pluin, sqlIdReg, parameter));
			} catch (Throwable e) {
				logger.error("plugin [StatementHandlerInterceptor] --> load plugin error! " + clazz, e);
			}
		}
	}
}
